{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "collapsed": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                                       user                song  play_count\n0  4e11f45d732f4861772b2906f81a7d384552ad12  SOCKSGZ12A58A7CA4B           1\n1  4e11f45d732f4861772b2906f81a7d384552ad12  SOCVTLJ12A6310F0FD           1\n2  4e11f45d732f4861772b2906f81a7d384552ad12  SODLLYS12A8C13A96B           3\ndata_train:\n                                           user                song  \\\n7971   7bdfc45af7e15511d150e2acb798cd5e4788abf5  SOXBCZH12A67ADAD77   \n31459  c405c586f6d7aadbbadfcba5393b543fd99372ff  SOXFYTY127E9433E7D   \n14683  625d0167edbc5df88e9fbebe3fcdd6b121a316bb  SONOYIB12A81C1F88C   \n\n       play_count  \n7971            8  \n31459           3  \n14683           1  \ndata_val:\n                                           user                song  \\\n26019  3325fe1d8da7b13dd42004ede8011ce3d7cd205d  SOURVJI12A58A7F353   \n33943  e82b3380f770c78f8f067f464941057c798eaca2  SOKNWRZ12A8C13BF62   \n15356  bdfca47d03157d26f1404075172128a6f8a3d39e  SOMNGMO12A6702187E   \n\n       play_count  \n26019          63  \n33943          19  \n15356           4  \n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "data = pd.read_csv(\"./data/triplet_dataset_sub.csv\")\n",
    "print(data.head(3))\n",
    "\n",
    "data_train, data_val = train_test_split(data, train_size=0.8, random_state=0)\n",
    "print(\"data_train:\\n{}\".format(data_train.head(3)))\n",
    "print(\"data_val:\\n{}\".format(data_val.head(3)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_play_count_by_user_song(df, user, song):\n",
    "    \"\"\"\n",
    "    根据user和song获得df中对应记录的play_count字段\n",
    "    :param df: 输入DataFrame对象\n",
    "    :param user: User名称\n",
    "    :param song: Song名称\n",
    "    :return: 对应的play_count值\n",
    "    \"\"\"\n",
    "    result = np.array(df.loc[df.user == user][df.song == song].play_count)\n",
    "    if np.size(result) > 0:\n",
    "        return result[0]\n",
    "    else:\n",
    "        return 0\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def init_user_songs(data):\n",
    "    \"\"\"\n",
    "    初始化user对应的songs列表\n",
    "    :param data: 原始User播放song记录\n",
    "    :return: \n",
    "    \"\"\"\n",
    "    user_songs = dict()\n",
    "    for each_user, each_value in data.groupby(by=\"user\"):\n",
    "        user_songs[each_user] = each_value.song.values\n",
    "    return user_songs\n",
    "\n",
    "\n",
    "def init_song_users(data):\n",
    "    \"\"\"\n",
    "    初始化song对应的users列表\n",
    "    :param data: 原始user播放song记录\n",
    "    :return: \n",
    "    \"\"\"\n",
    "    song_users = dict()\n",
    "    for each_song, each_value in data.groupby(by=\"song\"):\n",
    "        song_users[each_song] = each_value.user.values\n",
    "    \n",
    "    return song_users\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [],
   "source": [
    "def user_sim(user_1, user_2, user_songs):\n",
    "    \"\"\"\n",
    "    计算两个User的相似度\n",
    "    :param user_1: 1号User\n",
    "    :param user_2: 2号User\n",
    "    :return: 两个User的相似度\n",
    "    \"\"\"\n",
    "    songs_1_set = set(user_songs.get(user_1, list()))\n",
    "    songs_2_set = set(user_songs.get(user_2, list()))\n",
    "    intersection_num = len(songs_1_set.intersection(songs_2_set))\n",
    "    union_num = len(songs_1_set.union(songs_2_set))\n",
    "    \n",
    "    if union_num == 0:\n",
    "        return 0.0\n",
    "    else:\n",
    "        return 1.0 * intersection_num / union_num\n",
    "\n",
    "\n",
    "def song_sim(song_1, song_2, song_users):\n",
    "    \"\"\"\n",
    "    计算两首song的相似度\n",
    "    :param song_1: 1号song\n",
    "    :param song_2: 2号song\n",
    "    :param song_users: 原始User播放song的记录\n",
    "    :return: 两首song的相似度\n",
    "    \"\"\"\n",
    "    user_1_set = song_users.get(song_1, set())\n",
    "    user_2_set = song_users.get(song_2, set())\n",
    "    intersection_num = len(user_1_set.intersection(user_2_set))\n",
    "    union_num = len(user_1_set.union(user_2_set))\n",
    "    \n",
    "    if union_num == 0:\n",
    "        return 0.0\n",
    "    else:\n",
    "        return 1.0 * intersection_num / union_num\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "def init_user_sim_matrix(user_songs):\n",
    "    \"\"\"\n",
    "    计算User之间的相似度矩阵, 以及user_id和user索引的映射关系\n",
    "    :param user_songs: User-播放过的songs\n",
    "    :return: User相似度矩阵, user_id--user索引的映射关系\n",
    "    \"\"\"\n",
    "    user_size = len(user_songs.keys())\n",
    "    user_sim_matrix = np.zeros(dtype=np.float, shape=(user_size, user_size))\n",
    "    user_to_index = dict()\n",
    "    \n",
    "    user_ids = list(user_songs.keys())\n",
    "    \n",
    "    for i, user_id in enumerate(user_ids):\n",
    "        user_to_index[user_id] = i\n",
    "        \n",
    "        for j in range(i + 1, len(user_ids)):\n",
    "            each_sim = user_sim(user_id, user_ids[j], user_songs)\n",
    "            user_sim_matrix[i, j] = each_sim\n",
    "            user_sim_matrix[j, i] = each_sim\n",
    "            \n",
    "    return user_sim_matrix, user_to_index\n",
    "\n",
    "\n",
    "def init_song_sim_matrix(song_users):\n",
    "    \"\"\"\n",
    "    计算song之间的相似度矩阵，以及song和song索引的映射关系\n",
    "    :param song_users: song--播放过song的users\n",
    "    :return: song相似度矩阵, song和song索引的映射关系\n",
    "    \"\"\"\n",
    "    song_size = len(song_users.keys())\n",
    "    song_sim_matrix = np.zeros(dtype=np.float, shape=(song_size, song_size))\n",
    "    song_to_index = dict()\n",
    "    \n",
    "    songs = list(song_users.keys())\n",
    "    \n",
    "    for i, song in enumerate(songs):\n",
    "        song_to_index[song] = i\n",
    "        \n",
    "        for j in range(i + 1, len(songs)):\n",
    "            each_sim = song_sim(song, songs[j], song_users)\n",
    "            song_sim_matrix[i, j] = each_sim\n",
    "            song_sim_matrix[j, i] = each_sim\n",
    "            \n",
    "    return song_sim_matrix, song_to_index\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "\n",
    "def pred_user_cf(user, song, played_users_list, user_mean_scores, \n",
    "                 user_sim_matrix, user_to_index, df_train):\n",
    "    \"\"\"\n",
    "    预测user对song的打分\n",
    "    :param user: 目标user\n",
    "    :param song: 目标song\n",
    "    :param played_users_list: 播放过目标song的user列表\n",
    "    :param user_mean_scores: 每个user的平均打分\n",
    "    :param user_sim_matrix: 所有user间的相似度矩阵\n",
    "    :param user_to_index: user编号-user索引映射\n",
    "    :param df_train: 训练集数据\n",
    "    :return: \n",
    "    \"\"\"\n",
    "    pred_play_count = 0.0\n",
    "    total_weighted_count = 0.0\n",
    "    total_sim = 0.0\n",
    "    for each_user in played_users_list:\n",
    "        each_score = get_play_count_by_user_song(df_train,\n",
    "                                                 each_user,\n",
    "                                                 song)\n",
    "        each_sim = user_sim_matrix[user_to_index[each_user],\n",
    "                                   user_to_index[user]]\n",
    "        mean_score = user_mean_scores[each_user]\n",
    "        total_weighted_count += each_sim * (each_score - mean_score)\n",
    "        total_sim += each_sim\n",
    "    \n",
    "    if abs(total_sim) < 1e-6:\n",
    "        pred_play_count = 0.0\n",
    "    else:\n",
    "        pred_play_count = total_weighted_count / total_sim\n",
    "    \n",
    "    return pred_play_count\n",
    "\n",
    "\n",
    "def recommend_user_cf(user, song_users, user_mean_scores,\n",
    "                      user_sim_matrix, user_to_index, df_train):\n",
    "    \"\"\"\n",
    "    为指定user推荐songs\n",
    "    :param user: 目标user\n",
    "    :param song_users: 每个song-播放过该song的users映射\n",
    "    :param user_mean_scores: 每个user的平均打分\n",
    "    :param user_sim_matrix: 所有user之间的相似度矩阵\n",
    "    :param user_to_index: 每个user-对应的user索引映射\n",
    "    :param df_train: 训练集数据DataFrame\n",
    "    :return: 推荐结果\n",
    "    \"\"\"\n",
    "    rtn_songs = []\n",
    "    for song, played_users in song_users.items():\n",
    "        if user in played_users:\n",
    "            continue\n",
    "\n",
    "        played_users_list = sorted(list(played_users), \n",
    "                                   key=lambda user_x:\n",
    "                                   user_sim_matrix[user_to_index[user_x],\n",
    "                                                   user_to_index[user]],\n",
    "                                   reverse=True)\n",
    "        if len(played_users_list) > 10:\n",
    "            played_users_list = played_users_list[0:10]\n",
    "        \n",
    "        pred_count = pred_user_cf(user, song, played_users_list, \n",
    "                                  user_mean_scores, user_sim_matrix, \n",
    "                                  user_to_index, df_train)\n",
    "        rtn_songs.append((pred_count, song))\n",
    "\n",
    "    return sorted(rtn_songs, key=lambda x: x[0], reverse=True)\n",
    "\n",
    "\n",
    "def recommend_all_user_cf(df_train, df_val, rec_num):\n",
    "    \"\"\"\n",
    "    基于User的CF方法: 根据训练集的数据，对所有校验集中的User推荐Song\n",
    "    :param df_train: 训练集\n",
    "    :param df_val: 校验集\n",
    "    :param rec_num: 为每个User推荐的song数量\n",
    "    :return: \n",
    "    \"\"\"\n",
    "    result_dict = dict()\n",
    "    \n",
    "    print(\"\\n开始初始化user_songs映射\")\n",
    "    time_start = time.time()\n",
    "    user_songs = init_user_songs(df_train)\n",
    "    print(\"初始化user_songs映射完成，耗时{:.4f}秒\".format(time.time() - time_start))\n",
    "    \n",
    "    print(\"\\n开始初始化song_users映射\")\n",
    "    time_start = time.time()\n",
    "    song_users = init_song_users(df_train)\n",
    "    print(\"初始化song_users映射完成，耗时{:.4f}秒\".format(time.time() - time_start))\n",
    "    \n",
    "    print(\"\\n开始初始化user_mean_scores映射\")\n",
    "    time_start = time.time()\n",
    "    user_mean_scores = dict()\n",
    "    for user, songs in user_songs.items():\n",
    "        user_mean_scores[user] = np.mean([\n",
    "            get_play_count_by_user_song(df_train, user, song)\n",
    "            for song in songs])\n",
    "    print(\"初始化user_mean_scores映射完成，耗时{:.4f}秒\".format(time.time() - time_start))\n",
    "    \n",
    "    print(\"\\n开始初始化user_sim_matrix, user_to_index\")\n",
    "    time_start = time.time()\n",
    "    user_sim_matrix, user_to_index = init_user_sim_matrix(user_songs)\n",
    "    print(\"初始化user_sim_matrix, user_to_index完成，耗时{:.4f}秒\".format(\n",
    "        time.time() - time_start))\n",
    "    \n",
    "    val_users = df_val[\"user\"].unique()\n",
    "    print(\"\\n开始为{}个来自校验集的user推荐songs\".format(len(val_users)))\n",
    "    time_start = time.time()\n",
    "    for i, user in enumerate(val_users):\n",
    "        if user not in user_songs:\n",
    "            print(\"{} is a new user.\".format(user))\n",
    "            continue\n",
    "\n",
    "        rec_songs = recommend_user_cf(user, song_users, user_mean_scores,\n",
    "                                      user_sim_matrix, user_to_index, \n",
    "                                      df_train)\n",
    "        if len(rec_songs) > 0:\n",
    "            result_dict[user] = rec_songs[0: rec_num]\n",
    "        \n",
    "        if i % 100 == 0:\n",
    "            print(\"已经为{}个user计算好了推荐song的结果，耗时{:.4f}秒\".format(\n",
    "                i + 1, time.time() - time_start\n",
    "            ))\n",
    "    print(\"为{}个来自校验集的user推荐songs的工作已完成，耗时{:.4f}秒\".format(\n",
    "        len(val_users), time.time() - time_start\n",
    "    ))\n",
    "\n",
    "    return result_dict, len(song_users)\n",
    "\n",
    "\n",
    "def evaluate(user_rec_dict, total_song_num, df_val):\n",
    "    \"\"\"\n",
    "    评估在校验集上的预测结果\n",
    "    :param user_rec_dict: 预测结果<user-推荐的song和评分列表>\n",
    "    :param total_song_num: 训练集中的song总数\n",
    "    :param df_val: 校验集\n",
    "    :return: \n",
    "    \"\"\"\n",
    "    n_tp = 0                 # 校验集和预测结果匹配的song数\n",
    "    n_total_rec = 0          # 预测结果里的song数\n",
    "    n_total_real = 0         # 校验集里的song数\n",
    "    total_rec_songs = set()  # 预测结果里所有的song\n",
    "    rss_val = 0.0            # 预测结果与校验集结果的平方误差(用播放次数差来计算)\n",
    "    \n",
    "    unique_users = df_val[\"user\"].unique()\n",
    "    for user in unique_users:\n",
    "        real_songs = df_val.loc[df_val.user == user].song.values\n",
    "        n_total_real = n_total_real + len(real_songs)\n",
    "        \n",
    "        if user in user_rec_dict:\n",
    "            rec_songs = [x[1] for x in user_rec_dict[user]]\n",
    "            hit_songs = set(real_songs).intersection(set(rec_songs))\n",
    "        \n",
    "            total_rec_songs = total_rec_songs.union(hit_songs)\n",
    "            n_tp = n_tp + len(hit_songs)\n",
    "        \n",
    "            n_total_rec = n_total_rec + len(rec_songs)\n",
    "            \n",
    "            for pred_score, song in user_rec_dict[user]:\n",
    "                val_score = df_val.loc[df_val.user == user][df_val.song == song]\\\n",
    "                    .play_count.values\n",
    "                if len(val_score) > 0:\n",
    "                    rss_val = rss_val + (pred_score - val_score[0]) ** 2\n",
    "    \n",
    "    precision = 1.0 * n_tp / n_total_rec\n",
    "    recall = 1.0 * n_tp / n_total_real\n",
    "    coverage = 1.0 * len(total_rec_songs) / total_song_num\n",
    "    rmse = np.sqrt(1.0 * rss_val / df_val.shape[0])\n",
    "    \n",
    "    print(\"评价结束: precision={:.4f}, recall={:.4f}, coverage={:.4f}, rmse={:.4f}\".format(\n",
    "        precision, recall, coverage, rmse\n",
    "    ))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n开始初始化user_songs映射\n初始化user_songs映射完成，耗时0.1990秒\n\n开始初始化song_users映射\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "初始化song_users映射完成，耗时0.1910秒\n\n开始初始化user_mean_scores映射\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\Python37\\lib\\site-packages\\ipykernel_launcher.py:9: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n  if __name__ == '__main__':\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "初始化user_mean_scores映射完成，耗时188.7298秒\n\n开始初始化user_sim_matrix, user_to_index\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "初始化user_sim_matrix, user_to_index完成，耗时6.2234秒\n\n开始为726个来自校验集的user推荐songs\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "已经为1个user计算好了推荐song的结果，耗时47.9857秒\n"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-44-e2c2deec9f2f>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# 为每个校验集中的User推荐10首Song\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mresult_dict\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtotal_song_num\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mrecommend_all_user_cf\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata_train\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdata_val\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m10\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      3\u001b[0m \u001b[1;31m# 评价推荐结果\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m \u001b[0mevaluate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mresult_dict\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtotal_song_num\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdata_val\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m<ipython-input-41-c91afb1eff9c>\u001b[0m in \u001b[0;36mrecommend_all_user_cf\u001b[1;34m(df_train, df_val, rec_num)\u001b[0m\n\u001b[0;32m    114\u001b[0m         rec_songs = recommend_user_cf(user, song_users, user_mean_scores,\n\u001b[0;32m    115\u001b[0m                                       \u001b[0muser_sim_matrix\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0muser_to_index\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 116\u001b[1;33m                                       df_train)\n\u001b[0m\u001b[0;32m    117\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mrec_songs\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m>\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    118\u001b[0m             \u001b[0mresult_dict\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0muser\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mrec_songs\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mrec_num\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m<ipython-input-41-c91afb1eff9c>\u001b[0m in \u001b[0;36mrecommend_user_cf\u001b[1;34m(user, song_users, user_mean_scores, user_sim_matrix, user_to_index, df_train)\u001b[0m\n\u001b[0;32m     63\u001b[0m         pred_count = pred_user_cf(user, song, played_users_list, \n\u001b[0;32m     64\u001b[0m                                   \u001b[0muser_mean_scores\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0muser_sim_matrix\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 65\u001b[1;33m                                   user_to_index, df_train)\n\u001b[0m\u001b[0;32m     66\u001b[0m         \u001b[0mrtn_songs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mpred_count\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msong\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     67\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m<ipython-input-41-c91afb1eff9c>\u001b[0m in \u001b[0;36mpred_user_cf\u001b[1;34m(user, song, played_users_list, user_mean_scores, user_sim_matrix, user_to_index, df_train)\u001b[0m\n\u001b[0;32m     21\u001b[0m         each_score = get_play_count_by_user_song(df_train,\n\u001b[0;32m     22\u001b[0m                                                  \u001b[0meach_user\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 23\u001b[1;33m                                                  song)\n\u001b[0m\u001b[0;32m     24\u001b[0m         each_sim = user_sim_matrix[user_to_index[each_user],\n\u001b[0;32m     25\u001b[0m                                    user_to_index[user]]\n",
      "\u001b[1;32m<ipython-input-40-672d57ebabbf>\u001b[0m in \u001b[0;36mget_play_count_by_user_song\u001b[1;34m(df, user, song)\u001b[0m\n\u001b[0;32m      7\u001b[0m     \u001b[1;33m:\u001b[0m\u001b[1;32mreturn\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0m对应的play_count值\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      8\u001b[0m     \"\"\"\n\u001b[1;32m----> 9\u001b[1;33m     \u001b[0mresult\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0marray\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mloc\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mdf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0muser\u001b[0m\u001b[1;33m==\u001b[0m\u001b[0muser\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mdf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msong\u001b[0m\u001b[1;33m==\u001b[0m\u001b[0msong\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mplay_count\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     10\u001b[0m     \u001b[1;32mif\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msize\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m>\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     11\u001b[0m         \u001b[1;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\Python37\\lib\\site-packages\\pandas\\core\\indexing.py\u001b[0m in \u001b[0;36m__getitem__\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m   1408\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1409\u001b[0m             \u001b[0mmaybe_callable\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcom\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mapply_if_callable\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mobj\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1410\u001b[1;33m             \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_getitem_axis\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmaybe_callable\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0maxis\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0maxis\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1411\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1412\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m_is_scalar_access\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkey\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mTuple\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\Python37\\lib\\site-packages\\pandas\\core\\indexing.py\u001b[0m in \u001b[0;36m_getitem_axis\u001b[1;34m(self, key, axis)\u001b[0m\n\u001b[0;32m   1772\u001b[0m             \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_get_slice_axis\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0maxis\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0maxis\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1773\u001b[0m         \u001b[1;32melif\u001b[0m \u001b[0mcom\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mis_bool_indexer\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1774\u001b[1;33m             \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_getbool_axis\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0maxis\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0maxis\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1775\u001b[0m         \u001b[1;32melif\u001b[0m \u001b[0mis_list_like_indexer\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1776\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\Python37\\lib\\site-packages\\pandas\\core\\indexing.py\u001b[0m in \u001b[0;36m_getbool_axis\u001b[1;34m(self, key, axis)\u001b[0m\n\u001b[0;32m   1423\u001b[0m         \u001b[0mlabels\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mobj\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_get_axis\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maxis\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1424\u001b[0m         \u001b[0mkey\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcheck_bool_indexer\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlabels\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkey\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1425\u001b[1;33m         \u001b[0minds\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mkey\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnonzero\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1426\u001b[0m         \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1427\u001b[0m             \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mobj\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtake\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minds\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0maxis\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0maxis\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mKeyboardInterrupt\u001b[0m: "
     ],
     "output_type": "error"
    }
   ],
   "source": [
    "# 为每个校验集中的User推荐10首Song\n",
    "result_dict, total_song_num = recommend_all_user_cf(data_train, data_val, 10)\n",
    "# 评价推荐结果\n",
    "evaluate(result_dict, total_song_num, data_val)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
